package cn.zyl.demo.common.tools;

import cn.zyl.demo.common.enums.*;
import cn.zyl.demo.common.exception.ToolsException;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.util.Set;

/** SecurityTool 工具类说明:Java支持的安全方法Security工具
 * @author wsz
 * @date 2020-07-29
 * @version v1.0
 */
public class SecurityTool {
    private SecurityTool(){throw new IllegalAccessError("SecurityTool");}

    /**
     * 通过MessageDigest类消息摘要算法的工具类，获取字节码
     * @param cipherEnum 消息摘要的类型
     * @param charset 字符串编码类型
     * @param pendingStr 要处理的字符串
     * @throws ToolsException 处理失败
     * @return 字节数组
     */
    public static byte[] getBytes(CypherDigestEnum cipherEnum, CharsetEnum charset,String pendingStr)throws ToolsException{
        ToolsException.isNullThrow(charset, "字符编码为空");
        ToolsException.isTrueThrow(StringTool.isEmpty(pendingStr), "pendingStr 为空");
        MessageDigest messageDigest = getMessageDigest(cipherEnum);
        messageDigest.update(pendingStr.getBytes(charset.getType()));
        return messageDigest.digest();
    }

    /**
     * 获取指定的信息摘要类型
     * @param cipherEnum 指定的信息摘要
     * @throws ToolsException 获取失败
     * @return 消息摘要对象
     */
    public static MessageDigest getMessageDigest(CypherDigestEnum cipherEnum)throws ToolsException{
        ToolsException.isNullThrow(cipherEnum, "CypherDigestEnum 为空");
        try {
            return MessageDigest.getInstance(cipherEnum.getName());
        } catch (NoSuchAlgorithmException e) {
            throw new ToolsException("信息摘要类型未找到",e);
        }
    }
    /**
     * 获取指定的数字签名算法类型
     * @param cipherEnum 指定的数字签名算法
     * @throws ToolsException 获取失败
     * @return 数字签名算法对象
     */
    public static Signature getSignature(CypherSignatureEnum cipherEnum)throws ToolsException{
        ToolsException.isNullThrow(cipherEnum, "CypherSignatureEnum 为空");
        try {
            return Signature.getInstance(cipherEnum.getName());
        } catch (NoSuchAlgorithmException e) {
            throw new ToolsException("数字签名算法类型未找到",e);
        }
    }
    /**
     * 获取指定的密钥库类型
     * @param cipherEnum 指定的密钥库
     * @throws ToolsException 获取失败
     * @return 密钥库对象
     */
    public static KeyStore getKeyStore(CypherKeyStoreEnum cipherEnum)throws ToolsException{
        ToolsException.isNullThrow(cipherEnum, "CypherKeyStoreEnum 为空");
        try {
            return KeyStore.getInstance(cipherEnum.getName());
        } catch (KeyStoreException e) {
            throw new ToolsException("密钥库类型未找到",e);
        }
    }
    /**
     * 获取指定的非对称加密算法类型
     * @param cipherEnum 指定的非对称加密算法
     * @throws ToolsException 获取失败
     * @return 非对称加密算法对象
     */
    public static Cipher getCipher(CypherCipherEnum cipherEnum)throws ToolsException{
        ToolsException.isNullThrow(cipherEnum, "CypherCipherEnum 为空");
        try {
            return Cipher.getInstance(cipherEnum.getName());
        } catch (Exception e) {
            throw new ToolsException("非对称加密算法类型获取失败",e);
        }
    }
    /**
     * 获取指定的消息认证码算法
     * @param cipherEnum 指定的消息认证码算法
     * @throws ToolsException 获取失败
     * @return 消息认证码算法对象
     */
    public static Mac getMac(CypherMacEnum cipherEnum)throws ToolsException{
        ToolsException.isNullThrow(cipherEnum, "CypherCipherEnum 为空");
        try {
            return Mac.getInstance(cipherEnum.getName());
        } catch (Exception e) {
            throw new ToolsException("消息认证码算法类型获取失败",e);
        }
    }

    /**
     * 产生指定摘要算法的密钥
     * @param cypherEnum 消息认证码算法-类型
     * @return 密钥字节
     * @throws ToolsException 密钥生成失败
     */
    public static byte[] getKeyByHmac(CypherMacEnum cypherEnum)throws ToolsException{
        ToolsException.isNullThrow(cypherEnum, "cypherEnum 为空");
        try {
            // 初始化指定摘要算法的密钥产生器
            KeyGenerator generator = KeyGenerator.getInstance(cypherEnum.getName());
            // 产生密钥
            SecretKey secretKey = generator.generateKey();
            // 获得密钥
            return secretKey.getEncoded();
        }catch (NoSuchAlgorithmException e){
            throw new ToolsException(cypherEnum.getName()+"消息认证算法-生成密钥失败",e);
        }
    }
    private static void printList(){
        //获取 MessageDigest 支持的消息摘要类型
        System.out.println("MessageDigest(消息摘要)-列表：");
        Security.getAlgorithms("MessageDigest").forEach(x -> System.out.println(x+","));
        System.out.println("\nSignature(签名)-列表：");
        Security.getAlgorithms("Signature").forEach(System.out::println);
        System.out.println("\nCipher(密码)-列表：");
        Security.getAlgorithms("Cipher").forEach(System.out::println);
        System.out.println("\nMac(苹果机加密)-列表：");
        // MAC（Message Authentication Code，消息认证码算法）是含有密钥的散列函数算法，兼容了MD和SHA算法的特性，
        // 并在此基础上加入了密钥。消息的散列值由只有通信双方知道的秘密密钥K来控制，因次，我们也常把MAC称为HMAC（keyed-Hash Message Authentication Code）
        Security.getAlgorithms("Mac").forEach(System.out::println);
        System.out.println("\nKeyStore(密钥库)-列表：");
        Security.getAlgorithms("KeyStore").forEach(System.out::println);
    }
    public static void main(String[] args) {
        printList();
    }
}